/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.sistemas.sisgear.negocio;
import com.sistemas.sisgear.JSQLParser.TablesNamesFinder;
import com.sistemas.sisgear.dao.CampoFacade;
import com.sistemas.sisgear.dao.SeccionFacade;
import com.sistemas.sisgear.dao.TemplateFacade;
import com.sistemas.sisgear.entidades.Campo;
import com.sistemas.sisgear.entidades.Seccion;
import com.sistemas.sisgear.entidades.Template;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectItem;

/**
 *
 * @author PRE PRENSA01
 */
@Stateless
public class PlantillaNegocio {
    @EJB
    private SeccionFacade seccionFacade;
    @EJB
    private CampoFacade campoFacade;

    @EJB
    private TemplateFacade templateFacade;
    
    ArrayList<Integer> listaFooter = new ArrayList<Integer>();
    ArrayList<Integer> listaHeader = new ArrayList<Integer>();
    int numHeader, numFooter;

    ArrayList<SelectItem> listaSelect = new ArrayList<>();
    ArrayList<String> listaFrom = new ArrayList<>();
    ArrayList<OrderByElement> listaOrderBy = new ArrayList<>();

    Template plantilla;
    List<Seccion> listaSeccion = new ArrayList<>();
    List<Campo> listaCampo = new ArrayList<>();

    ResultSet rs, rs_aux;
    boolean existeH = false, existeD = false, existeF = false;
    @PersistenceContext(unitName = "com.mycompany_Pruebamaven_war_1.0-SNAPSHOTPU")
    private EntityManager em;

    // Add business logic below. (Right-click in editor and choose
    // "Insert Code > Add Business Method")
    public List<Template> findAll() {
        return templateFacade.findAll();
    }
//
    public Template plantillaPorId(String id) {
        return templateFacade.find(id);
    }
    
    public Integer cantidadPlantillas(){
        return templateFacade.count();
    }
    
    public Integer cantidadSecciones(){
        return seccionFacade.count();
    }
    
    public Integer cantidadCampos(){
        return campoFacade.count();
    }
    
    public void guardarPlantilla(Template p){
        templateFacade.create(p);
    }

    public List<Seccion> obtenerSecciones(String idTmp) {
        TypedQuery<Seccion> query = em.createNamedQuery("Seccion.todosDePlantilla", Seccion.class);
        query.setParameter("codigo", idTmp);
        return query.getResultList();
    }

    public List<Campo> obtenerCampos(String idScc) {
        TypedQuery<Campo> query = em.createNamedQuery("Campo.todosDeSeccion", Campo.class);
        query.setParameter("codigo", idScc);
        return query.getResultList();
    }

    public void cargarListas(String sql) {

        TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();

        CCJSqlParserManager pm = new CCJSqlParserManager();
        Statement statement = null;
        try {
            statement = pm.parse(new StringReader(sql));
        } catch (JSQLParserException ex) {
            Logger.getLogger(PlantillaNegocio.class.getName()).log(Level.SEVERE, null, ex);
        }

        Select selectStatement = (Select) statement;

        listaFrom = (ArrayList<String>) tablesNamesFinder.getTableList(selectStatement);
        listaOrderBy = (ArrayList<OrderByElement>) tablesNamesFinder.getOrderByElements(selectStatement);
        listaSelect = (ArrayList<SelectItem>) tablesNamesFinder.getSelectElements(selectStatement);
    }
    
    public void cargarNumHdrFtr() {
        int h = 1, f = 1;
        for (Seccion S : listaSeccion) {
            if (S.getTipo().equalsIgnoreCase("H")) {
                listaHeader.add(h);
                numHeader++;
                h++;
                //validamos de paso su existencia
                existeH = true;
            }
            if (S.getTipo().equalsIgnoreCase("D")) {
                //validamos de paso su existencia
                existeD = true;
            }
            if (S.getTipo().equalsIgnoreCase("F")) {
                //listaFooter.add(Integer.parseInt(S.getNivel()));
                listaFooter.add(Integer.parseInt(S.getNivel()));
                numFooter++;
                f++;
                //validamos de paso su existencia
                existeF = true;
            }
        }
    }

    public void generarArchivo(String idTmp, String tipo) throws SQLException, JSQLParserException {
        Conectadb();
        conectar();
        ArrayList<String> filaAnterior = null;
        int i = 0;
        plantilla = plantillaPorId(idTmp);
        rs = consulta(plantilla.getConsulta());
        rs_aux = consulta(plantilla.getConsulta());
        cargarListas(plantilla.getConsulta());
        listaSeccion = obtenerSecciones(idTmp);
        cargarNumHdrFtr();
        System.out.println("LISTAAAAAAAAAAAAAAA:"+ listaFooter.get(0));
        System.out.println("LISTAAAAAAAAAAAAAAA:"+ listaFooter.size());
        
        while (rs.next()) {
            if (i == 0) {
                if (this.existeH) {
                    imprimiHeader(tipo);
                }
                if (this.existeD) {
                    imprimirDetail(tipo);
                }
                i++;

            } else {
                rs_aux.next();
                if (detectarCambios(filaAnterior)) {
                    //Mostrar(this.listaHeader);  
                    if (this.existeF) {
                        imprimirFooter(tipo);
                    }
                    if (this.existeH) {
                        imprimiHeader(tipo);
                    }
                    if (this.existeD) {
                        imprimirDetail(tipo);
                    }
                    } else {
                    if (this.existeD) {
                        imprimirDetail(tipo);
                    }
                }
             }
            filaAnterior = guardarFilaAnterior();
            //Mostrar(filaAnterior);
            //this.instanciarLista(listaHeader, plantilla.getNumNivelesHeader());
            if(!rs_aux.next()){
                System.out.println("TERMINANDO");
                System.out.println("..."+rs_aux.getObject("E.ANO"));
            }
        }
        //cerrarFile(tipo);
    }

    public void imprimiHeader(String tipo) throws SQLException {
        int nivel = 0;
        List<Campo> camposHeader = new ArrayList<>();
        if (!listaHeader.isEmpty()) {
            if(tipo.equalsIgnoreCase("xml"))
                System.out.println("<HEADER>");
            
            for (Integer listaHeader1 : listaHeader) {
                nivel = listaHeader1;
                Seccion header = obtenerSeccion("H", ""+nivel);
                camposHeader = obtenerCampos(header.getIdSeccion());

                for (Campo campo : camposHeader) {
                    Object campoH = obtenerCampo(campo);
                    if (tipo.equalsIgnoreCase("plano")){
                        System.out.println(campoH);
                    } else {
                        System.out.println("<" + nombreCol(campo) + ">" + campoH + "</" + nombreCol(campo) + ">");
                    }
                }
            }
            if(tipo.equalsIgnoreCase("xml"))
                System.out.println("</HEADER>");
        }
    }

    private void imprimirDetail(String tipo) throws SQLException {
        List<Campo> camposDetail;
        Seccion detail = obtenerSeccion("D", "" + 0);
        camposDetail = obtenerCampos(detail.getIdSeccion());
        if(tipo.equalsIgnoreCase("xml"))
            System.out.println("<REGISTRO>");
        for (Campo campo : camposDetail) {
            Object campoD = obtenerCampo(campo);
            if (tipo.equalsIgnoreCase("plano")) {
                System.out.println(campoD);
            } else {
                System.out.println("<" + nombreCol(campo) + ">" + campoD + "</" + nombreCol(campo) + ">");
            }

        }
        System.out.println("");
        if(tipo.equalsIgnoreCase("xml"))
            System.out.println("< />");
    }
    
    public void cerrarFile(String tipo) throws SQLException{
        List<Campo> camposFooter;
        Collections.sort(listaFooter);
        
        if(tipo.equalsIgnoreCase("xml"))
            System.out.println("<FOOTER>");
        
        for(int i=listaFooter.size()-1;i>=0;i--){
           Seccion footer = obtenerSeccion("F", ""+i);
            camposFooter = obtenerCampos(""+footer.getIdSeccion());
            for (Campo campo : camposFooter) {
                    String nombre = campo.getColumnaQ();
                    Object campoF = rs_aux.getObject(nombre);
                if (tipo.equalsIgnoreCase("plano")) {
                    System.out.println(campoF);
                } else {
                    System.out.println("<" + nombreCol(campo) + ">" + campoF + "</" + nombreCol(campo)+ ">");
                } 
            }
        }
        if(tipo.equalsIgnoreCase("xml"))
            System.out.println("</FOOTER>");
    }
    
    public void imprimirFooter(String tipo) throws SQLException {
        List<Campo> camposFooter;
          //System.out.println("tamaño :"+listaHeader.size());
        for (int nivel = listaHeader.size() - 1; nivel >= 0; nivel--) {
          //System.out.println("nivel "+listaHeader.get(nivel));
            if(tipo.equalsIgnoreCase("xml"))
                System.out.println("<FOOTER>");
            if (listaFooter.contains(listaHeader.get(nivel))) {
                Seccion footer = obtenerSeccion("F", ""+listaHeader.get(nivel));
                camposFooter = obtenerCampos(""+footer.getIdSeccion());
                for (Campo campo : camposFooter) {
                    String nombre = campo.getColumnaQ();
                    Object campoF = rs_aux.getObject(nombre);
                    if (tipo.equalsIgnoreCase("plano")) {
                        System.out.println(campoF);
                    } else {
                        System.out.println("<" + nombreCol(campo) + ">" + campoF + "</" + nombreCol(campo)+ ">");
                    }
                }
            }
            if(tipo.equalsIgnoreCase("xml"))
                System.out.println("</FOOTER>");
        }
    }
    
    public Seccion obtenerSeccion(String tipo, String nivel) {
        for (Seccion S : listaSeccion) {
            if (S.getTipo().equalsIgnoreCase(tipo) && S.getNivel().equalsIgnoreCase(nivel)) {
                return S;
            }
        }
        return null;
    }

    public Object obtenerCampo(Campo campo){
        String nombre = campo.getColumnaQ();
        try {
            return rs.getObject(nombre);
        } catch (SQLException ex) {
            Logger.getLogger(PlantillaNegocio.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    
    public boolean detectarCambios(ArrayList<String> filaAnterior) throws SQLException {
        boolean cambio = false;
        for (int i = 0; i < listaOrderBy.size(); i++) {
            if (!filaAnterior.get(i).equals(rs.getObject(listaOrderBy.get(i).toString()).toString())) {
                cambio = true;
                this.listaHeader.clear();
                for (int j = i + 1; j <= numHeader ; j++) {
                    listaHeader.add(j);
                }
                break;
            }
        }
        return cambio;
    }
    

    public String nombreCol(Campo c) {
        return c.getColumnaQ();
    }

    public ArrayList<String> guardarFilaAnterior() throws SQLException {
        ArrayList<String> Campos = new ArrayList<>();
        //System.out.println("TAM ORDERBY: "+listaOrderBy.size());
        Mostrar(Campos);
        
        for (int i = 0; i < this.listaOrderBy.size(); i++) {
            Campos.add(rs.getObject(listaOrderBy.get(i).toString()).toString());
        }
        return Campos;
    }

//variables miembro
    private String usuario;
    private String clave;
    private String url;
    private String driverClassName;
    private Connection conn = null;
    private java.sql.Statement estancia;

//CONSTRUCTORES
    //Constructor que toma los datos de conexion por medio de parametros
    public void Conectadb(String usuario, String clave, String url, String driverClassName) {
        this.usuario = usuario;
        this.clave = clave;
        this.url = url;
        this.driverClassName = driverClassName;
    }

    //Constructor que crea la conexion sin parametros con unos definidos en la clase
    //(meter los datos correspondientes)
    public void Conectadb() {
        //poner los datos apropiados
        this.usuario = "root";
        this.clave = "pass";
        this.url = "jdbc:mysql://localhost:3306/ds_pruebas?zeroDateTimeBehavior=convertToNull";
        this.driverClassName = "com.mysql.jdbc.Driver";
        System.out.println("CONECTADO!!!");
    }

//la conexion propiamente dicha
    public void conectar() throws SQLException {
        try {
            Class.forName(this.driverClassName).newInstance();
            this.conn = DriverManager.getConnection(this.url, this.usuario, this.clave);

        } catch (Exception err) {
            System.out.println("Error " + err.getMessage());
        }
    }
    //Cerrar la conexion

    public void cierraConexion() throws SQLException {
        this.conn.close();
    }

    public ResultSet consulta(String consulta) throws SQLException {
        this.estancia = (java.sql.Statement) conn.createStatement();
        return this.estancia.executeQuery(consulta);
    }

    public void Mostrar(ArrayList lista) {
        for (int i = 0; i < lista.size(); i++) {
            System.out.print(" " + lista.get(i).toString());
        }
        System.out.println("");
    }    
    
    public void recuperandoTmp() throws SQLException{
        Conectadb();conectar();
        Template t = plantillaPorId("T1");
        System.out.println("Su query: "+ t.getConsulta());
        mostrarQuery(t.getConsulta());
        listaSeccion = obtenerSecciones("T1");
        System.out.println(listaSeccion.get(0).getTipo());
        
        cargarListas("select e.nombre, p.descripcion, f.Nombres, f.Apellidos\n" +
"   from contrato c, equipo e, futbolista f, posicion p\n" +
"   where c.equipo_idEquipo=e.idEquipo and c.Futbolista_idFutbolista=f.idFutbolista and f.Posicion_idPosicion=p.idPosicion\n" +
"   order by e.nombre, p.descripcion;");
        Mostrar(listaOrderBy);

    }
    public void mostrarQuery(String sql) throws SQLException{
        ResultSet rs = consulta(sql);
        ResultSetMetaData rsMd = rs.getMetaData();

        while (rs.next()) {
            for (int i = 0; i < rsMd.getColumnCount(); i++) {
                System.out.print(rs.getObject(i + 1) + " ");
                //System.out.println("CHAU FOR");                
                //break;
            }
            //System.out.println("CHAU WHILE");
            //break;
            System.out.println("");
        }
        
    }

}
